package com.yf.internedstring;

import org.junit.Test;

/**
 * 测试字符串常量池的4个规则
 * 1、常量池中不会存在相同内容的常量
 * 2、常量与常量拼接，结果在字符串常量池中（原理：编译期优化）
 * 3、参与拼接中只要有一个是变量，结果就在堆中。变量拼接的原理是StringBuilder
 * 4、如果拼接的结果调用intern(), 则主动将常量池中还没有的字符串对象放入池中，并返回该字符串对象地址
 */
public class StringTableTest {
    /*
    1、常量与常量拼接，结果在字符串常量池中（原理：编译期优化）
    分析方法：
        - 找开在idea中打开编译后的class文件
        - 使用jclasslib 查看字节码指令
     */
    @Test
    public void test1() {
        String s1 = "a" + "b" + "c"; // 等同于"abc"，在生成class文件时，编译器会优化为 String s1 = "abc"
        String s2 = "abc"; // 字符串字面量一定是存放在字符串常量池中的

        System.out.printf("s1 == s2 -> %s\n", s1 == s2); // true
    }

    @Test
    public void test2() {
        String s1 = "javaee"; // 在String pool中
        String s2 = "hadoop"; // 在String pool中

        String s3 = "javaeehadoop"; // 在String pool中
        String s4 = "javaee" + "hadoop"; // 编译期优化为"javaeehadoop"，在String pool中

        /*
        3、只要拼接的成员中有一个是变量，就会调用StringBuilder，结果存放到堆中
         */
        String s5 = s1 + "hadoop"; // 字符串拼接中包含变量则调用StringBuilder，结果在堆中
        String s6 = "javaee" + s2; // 同上，结果在堆中
        String s7 = s1 + s2; // 同上，结果在堆中

        /*
        2、常量池中不会存在相同内容的常量
         */
        System.out.printf("s3 == s4 -> %s\n", s3 == s4); // true
        System.out.printf("s3 == s5 -> %s\n", s3 == s5); // false
        System.out.printf("s3 == s6 -> %s\n", s3 == s6); // false
        System.out.printf("调用s7.intern()前，s3 == s7 -> %s\n", s3 == s7); // false
        System.out.printf("s5 == s6 -> %s\n", s5 == s6); // false
        System.out.printf("s5 == s7 -> %s\n", s5 == s7); // false
        System.out.printf("s6 == s7 -> %s\n", s6 == s7); // false
        /*
        4、intern方法判断字符串常量池中是否存在变量引用的字符串
        如果有就返回；
        如果没有就在字符串常量池中创建该字符串，并返回。
         */
        s7.intern();
        System.out.printf("调用s7.intern()后，s3 == s7 -> %s\n", s3 == s7); // true
        String s8 = s7.intern();
        System.out.printf("s3 == s8 -> %s\n", s3 == s8); // true
    }
}
